package com.scrcu.cloud.wechat.home.endpoint.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.scrcu.cloud.wechat.home.endpoint.common.exception.BusiException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @auther: siliang liu
 * @date: 2024/3/4 11:05
 * @description: http工具类封装
 * @version: 1.0.0
 */
@Slf4j
@Component
public class HttpUtils {

    private static volatile OkHttpClient.Builder okHttpClientBuilder = null;

    private Map<String, Object> paramMap;

    private Map<String, String> headerMap;

    private Request.Builder request;

    private String url;

    public static final String MEDIA_TYPE_JSON = "application/json; charset=utf-8";

    public static final String DEFAULT_CHARSET = "utf-8";

    @Value("${http.connect-timeout}")
    private int connectTimeOut;

    @Value("${http.read-timeout}")
    private int readTimeOut;

    @Value("${http.write-timeout}")
    private int writeTimeOut;

    public static String host;

    public static int port;

    @Value("${http.proxy.host}")
    private String proxyHost;

    @Value("${http.proxy.port}")
    private int proxyPort;

    @PostConstruct
    public void init() {
        host = this.proxyHost;
        port = this.proxyPort;
        if (okHttpClientBuilder == null) {
            synchronized (HttpUtils.class) {
                TrustManager[] trustManagers = buildTrustManagers();
                if (okHttpClientBuilder == null) {
                    okHttpClientBuilder = new OkHttpClient.Builder()
                            .connectTimeout(connectTimeOut, TimeUnit.SECONDS)
                            .writeTimeout(writeTimeOut, TimeUnit.SECONDS)
                            .readTimeout(readTimeOut, TimeUnit.SECONDS)
                            .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0])
                            .hostnameVerifier((hostname, session) -> true)
                            .retryOnConnectionFailure(true);
                }

            }
        }
    }

    /**
     * 创建http客户端
     */
    private HttpUtils() {
    }


    /**
     * 创建httpUtils
     */
    public static HttpUtils builder() {
        return new HttpUtils();
    }

    /**
     * 创建httpUtils
     */
    public static HttpUtils builder(boolean isProxy) {
        HttpUtils httpUtils = new HttpUtils();
        if (isProxy) {
            InetSocketAddress socketAddress = new InetSocketAddress(host, port);
            okHttpClientBuilder.proxy(new Proxy(Proxy.Type.HTTP, socketAddress));
        }
        return httpUtils;
    }

    /**
     * 添加url
     *
     * @param url url
     */
    public HttpUtils url(String url) {
        this.url = url;
        return this;
    }

    /**
     * 添加参数
     *
     * @param key   参数
     * @param value 值
     */
    public HttpUtils addParam(String key, String value) {
        if (paramMap == null) {
            paramMap = new LinkedHashMap<>();
        }
        paramMap.put(key, value);
        return this;
    }

    /**
     * 添加参数
     *
     * @param param 参数
     */
    public HttpUtils body(Map<String, ?> param) {
        if (paramMap == null) {
            paramMap = new LinkedHashMap<>();
        }
        paramMap.putAll(param);
        return this;
    }

    /**
     * 添加参数
     *
     * @param object 参数
     */
    public HttpUtils body(JSONObject object) {
        if (paramMap == null) {
            paramMap = new LinkedHashMap<>();
        }
        paramMap.putAll(object);
        return this;
    }

    /**
     * 添加请求头
     *
     * @param key   参数
     * @param value 值
     */
    public HttpUtils addHeader(String key, String value) {
        if (headerMap == null) {
            headerMap = new LinkedHashMap<>();
        }
        headerMap.put(key, value);
        return this;
    }

    /**
     * 初始化get方法
     */
    public HttpUtils get() {
        request = new Request.Builder().get();
        StringBuilder urlBuilder = new StringBuilder(url);
        if (paramMap != null) {
            urlBuilder.append(url.contains("?") ? "&" : "?");
            try {
                for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                    urlBuilder.append(URLEncoder.encode(entry.getKey(), DEFAULT_CHARSET))
                            .append("=")
                            .append(URLEncoder.encode((String) entry.getValue(), DEFAULT_CHARSET))
                            .append("&");
                }
            } catch (UnsupportedEncodingException exception) {
                throw new RuntimeException("调用http接口编码url异常", exception);
            }
            urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        }
        log.info("get请求：{}", urlBuilder);
        request.url(urlBuilder.toString());
        return this;
    }

    /**
     * 初始化post方法
     *
     * @param isForm true：表单格式数据
     *               false/空：json格式数据
     */
    public HttpUtils post(boolean isForm) {
        RequestBody requestBody;
        if (isForm) {
            FormBody.Builder formBody = new FormBody.Builder();
            if (paramMap != null) paramMap.forEach((key, value) -> {
                formBody.add(key, (String) value);
            });
            requestBody = formBody.build();
            log.info("post请求：{}，参数：{}", url, paramMap);
        } else {
            String json = "";
            if (paramMap != null) json = JSON.toJSONString(paramMap);
            log.info("post请求：{}，参数：{}", url, json);
            requestBody = RequestBody.create(MediaType.parse(MEDIA_TYPE_JSON), json);
        }
        request = new Request.Builder().post(requestBody).url(url);
        return this;
    }

    /**
     * 初始化post方法
     * json格式数据
     */
    public HttpUtils post() {
        RequestBody requestBody;
        String json = "";
        if (paramMap != null) json = JSON.toJSONString(paramMap);
        log.info("post请求：{}，参数：{}", url, json);
        requestBody = RequestBody.create(MediaType.parse(MEDIA_TYPE_JSON), json);
        request = new Request.Builder().post(requestBody).url(url);
        return this;
    }

    /**
     * 同步执行
     */
    public String execute() {
        setHeader(request);
        try (Response response = okHttpClientBuilder.build().newCall(request.build()).execute()) {
            if (response.code() == 200) {
                ResponseBody body = response.body();
                String resultStr = body == null ? "" : body.string();
                log.info("http调用：{}成功，返回结果：{}", url, resultStr);
                return resultStr;
            }
            throw new BusiException(String.valueOf(response.code()), response.message());
        } catch (IOException e) {
            throw new RuntimeException("http调用：" + url + "异常", e);
        }
    }

    /**
     * 同步执行
     */
    public InputStream executeStream() {
        setHeader(request);
        try (Response response = okHttpClientBuilder.build().newCall(request.build()).execute()) {
            if (response.code() == 200) {
                ResponseBody body = response.body();
                InputStream resultStr = body == null ? null : body.byteStream();
                log.info("http调用：{}成功，返回结果：InputStream", url);
                return resultStr;
            }
            throw new BusiException(String.valueOf(response.code()), response.message());
        } catch (IOException e) {
            throw new RuntimeException("http调用：" + url + "异常", e);
        }
    }

    /**
     * 同步执行
     */
    public <T> T execute(Class<T> clazz) {
        return JSONObject.parseObject(execute(), clazz);
    }

    /**
     * 添加请求头
     */
    private void setHeader(Request.Builder request) {
        if (headerMap == null) request.addHeader("content-type", MEDIA_TYPE_JSON);
        if (headerMap != null) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                request.addHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 生成安全套接字工厂（绕过SSL验证）
     */
    private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustManagers) {
        SSLSocketFactory ssFactory;
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustManagers, new SecureRandom());
            ssFactory = sc.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return ssFactory;
    }

    /**
     * 使用自定义的X509TrustManager信任所有证书
     */
    private static TrustManager[] buildTrustManagers() {
        return new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {

                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {

                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };
    }
}